package com.example.batch.core;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.validation.Validator;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 抽象数据处理器
 * 提供通用的数据处理、验证和匹配功能
 */
@Slf4j
public abstract class AbstractDataProcessor<S, T> implements DataProcessor<S, T> {
    
    // Bean验证器
    @Autowired
    protected Validator validator;
    
    /**
     * 验证目标对象
     * @param target 待验证的对象
     * @return 验证结果
     */
    @Override
    public ValidationResult validate(T target) {
        // 执行Bean验证
        Set<ConstraintViolation<T>> violations = validator.validate(target);
        if (violations.isEmpty()) {
            return ValidationResult.success();
        }
        
        // 收集验证错误信息
        List<String> errors = violations.stream()
                .map(v -> v.getPropertyPath() + ": " + v.getMessage())
                .collect(Collectors.toList());
                
        return ValidationResult.failure(errors, target);
    }
    
    /**
     * 数据匹配处理
     * @param sources 源数据列表
     * @return 匹配结果,包含需要更新和插入的数据
     */
    @Override
    public MatchResult<T> match(List<T> sources) {
        // 查找已存在的数据
        List<T> existingData = findExistingData(sources);
        
        // 构建已存在数据的映射
        Map<Object, T> existingMap = existingData.stream()
                .collect(Collectors.toMap(this::getKey, Function.identity()));
                
        List<T> toUpdate = new ArrayList<>();
        List<T> toInsert = new ArrayList<>();
        
        // 分类处理:更新或插入
        for (T source : sources) {
            if (existingMap.containsKey(getKey(source))) {
                toUpdate.add(source);
            } else {
                toInsert.add(source);
            }
        }
        
        return new MatchResult<>(toUpdate, toInsert);
    }
    
    /**
     * 获取实体的主键
     * 子类需要实现此方法以提供实体的唯一标识
     */
    protected abstract Object getKey(T entity);
    
    /**
     * 查找已存在的数据
     * 子类需要实现此方法以提供数据查询逻辑
     */
    protected abstract List<T> findExistingData(List<T> sources);
} 